// 0.如果使用模块化机制编程,导入Vue和VueRouter,要调用Vue.use(VueRouter)

// 1.定义(路由)组件
// 可以从其他文件 import 进来
const Foo = {template:'<div>foo</div>'}
const Bar = {template:'<div>bar</div>'}

// 2.定义路由
// 每个路由应该映射一个组件。其中"component"可以是
// 通过Vue.extend() 创建的组件构造器
// 或者,只是一个组件配置对象
// 我们晚点再讨论嵌套路由

const routes=[
    {path:'/foo',component:Foo},
    {path:'/bar',component:Bar}
]

// 3.创建 router 实例，然后传 `routes`配置
// 你还可以传别的配置参数，不过先这么简单着吧
const router = new VueRouter({
    routes 
})

// 4.创建和挂载根实例。
// 记得要通过 router 配置参数注入路由。
// 从而让整个应用都有路由功能
const app = new Vue({
    router
}).$mount('#app')


// 动态路由匹配(动态路由参数)
 const User = {
     template:'<div>User</div>'
 }

 const router = new VueRouter({
     routes:[
        //  动态路径参数 以冒号开头
        {path:'/user/:id',component:User}
     ]
 })

 const User = {
     template:'<div>User {{ $route.params.id }}</div>'
 }

// example 
//     模式                             匹配路径                  $route.params
// /user/:username                    /user/evan               {username:'evan'}
// /user/:username/post/:post_id      /user/evan/post/123      {username:'evan',post_id:'123}

// 响应路由参数的变化
const User = {
    template:'...',
    watch:{
        '$route' (to,from){
            // 对路由变化作出响应
        }
    }
}

// 或者使用2.2中引入的 beforeRouteUpdate  导航守卫:
const User = {
    template:'...',
    beforeRouteUpdate(to,from,next){
        // react to route changes...
        // do not forget to call next()
    }
}



// 通配符   * 
// 含有通配符 * 的路由应该放到最后，路由{path:'*'} 通常用于客户端404错误。

// 给出一个路由 { path: '/user-*' }
this.$router.push('/user-admin')
this.$router.params.pathMatch //'admin'
//给出一个路由 { path: '*'}
this.$router.push('/non-existing')
this.$route.params.pathMatch // 'non-existing'

// 嵌套路由
const router = new VueRouter({
    routes:[
        {   path:'/user/:id',component:User,
            children:[
                {
                    // 当 /user/:id/profile 匹配成功,
                    // UserProfile 会被渲染在User的<router-view>中
                    path:'profile',
                    component:UserProfile
                },
                {
                    // 当 /user/:id/posts  匹配成功
                    // UserPosts 会被渲染在User 的 <router-link>中
                    path: 'posts',
                    component: UserPosts
                }
            ]
        }
    ]
})


// 编程式的导航 ---1                声明式导航
// this.$router.push(...)          <router-link :to="..."></router-link>

// 字符串
router.push('home')

// 对象
router.push({path:'home'})

//命名的路由
router.push({name:'user',params:{userId:'123'}})

// 带查询参数，变成 /register?plan=private
router.push({path:'register',query:{plan:'private'}})
// 接收  
this.$route.query;

// router.replace(location, onComplete?, onAbort?)

// 替换掉当前的 history 记录。
// 编程式的导航 ---2                声明式导航
// router.replace(...)        <router-link :to="..."></router-link>


// router.go(n)  <===>  window.history.go(n)

// 在浏览器记录中前进一步，等同于 history.forward()
router.go(1)

// 后退一步记录，等同于 history.back()
router.go(-1)

// 前进 3 步 记录
router.go(3)

// 如果 history 记录不够用，那就默默地失败呗
router.go(-100)
router.go(100)


// 命名视图
{/* <router-view class="view one"></router-view>
<router-view class="view two" name="a"></router-view>
<router-view class="view three" name="b"></router-view> */}

const router = new VueRouter({
    routes:[
        {
            path:'/',
            components:{
                default:Foo,
                a:Bar,
                b:Baz
            }
        }
    ]
})


//  UserSettings.vue
<div>
    <h1>User Settings</h1>
    <NavBar />
    <router-view />
    <router-view name="helper"/>
</div>


{
    path:'/settings',
    // 你也可以在定级路由就配置命名视图
    component:UserSettings,
    children:[{
        path:'emails',
        component:UserEmailsSubscriptions
    },{
        path:'profile',
        components:{
            default:UserProfile,
            helper:UserProfilePreview
        }
    }]
}

// 重命名和别名
const router = new VueRouter({
    routes:[
        {
            path:'/a',redirect:'/b'
        }
    ]
})

// 重定向的目标也可以是一个命名的路由:
const router = new VueRouter({
    routes:[
        {   path: '/a',redirect:{name:'foo'}}
    ]
})

// 甚至是一个方法,动态返回重定向目标:
const router = new VueRouter({
    routes:[
        {   path:'/a',redirect:to=>{
            // 方法接收 目标路由 作为参数
            // return 重定向的  字符串路径/路径对象
        }}
    ]
})


// 别名 alias
const router = new VueRouter({
    routes:[
        {path:'/a',component:A,alias:'/b'}
    ]
})


// 路由组件传参
// 1.取代与$route 的耦合
const User = {
    template:'<div>User {{$route.params.id}}</div>'
}

const router = new VueRouter({
    routes:[
        {path:'/user/:id',component:User}
    ]
})

// 2.通过 props 解耦
const User = {
    props:['id'],
    template:'<div>User {{ id }}</div>'
}

const router = new VueRouter({
    routes:[
        {path:'/user/:id',component:User,props:true},

        // 对于包含命名视图的路由，你必须分别为每个命名视图添加`props`选项
        {
            path:'/user/:id',
            components:{default:User,sidebar:Sidebar},
            props:{default:true,sidebar:false}    
        }
    ]
})


// 对象模式
// 如果 props 是一个对象，它会被按原样设置为组件属性。当 props 是静态的时候有用。

const router = new VueRouter({
  routes: [
    { path: '/promotion/from-newsletter', component: Promotion, props: { newsletterPopup: false } }
  ]
})

// # 函数模式
// 你可以创建一个函数返回 props。这样你便可以将参数转换成另一种类型，将静态值与基于路由的值结合等等。

const router = new VueRouter({
    routes:[
        {path:'/search',component:SearchUser,props:(route)=>({query:route.query.q})}
    ]
})

// URL  /search?q=vue  会将 {query:'vue'} 作为属性传递给 SearchUser 组件


// HTML5 History 模式----充分利用history.pushState API来完成URL跳转而无须重新加载页面
const router = new VueRouter({
    mode:'history',
    routes:[{
        
    }]
})


// 导航守卫----
// ----beforeRouteUpdate的组件内守卫
// ###---全局前置守卫---router.beforeEach 注册一个全局前置守卫:
const router = new VueRouter({
    // ...
})

router.beforeEach((to,from,next)=>{
    // ...
})

// 全局后置钩子
// 你也可以注册全局后置钩子，然而和守卫不同的是，这些钩子不会接受next的函数，也不会改变导航本身:

router.afterEach((to,from) => {
    // ...
})


// 路由独享的守卫
// 你可以在路由配置上直接定义 beforeEnter 守卫:
const router = new VueRouter({
    routes:[
        {
            path:'/foo',
            component:Foo,
            beforeEnter:(to,from,next) =>{
                // ...
            }
        }
    ]
})

// 组件内的守卫
// ---最后，你可以在路由组件内直接定义一下路由导航守卫

const Foo = {
    template:`...`,
    beforeRouteEnter (to, from, next) {
        // ...
        // 在渲染该组件的对用路由被confirm前调用
        // 不！能！获取组件实例`this`
        // 因为当守卫执行前,组件实例还没被创建
    },
    
    beforeRouteUpdate(to,from,next){
        // ...
        // 在当前路由改变，但是该组件被复用时调用
        // 举例来说，对于一个带有动态参数的路径，/foo/:id,在/foo/1 和 /foo/2之间 跳转的时候
        // 由于会渲染同样的Foo组件，因此组件实例会被复用。而这个钩子就会在这个情况下被调用
    },
    
    // 离开守卫通常用来禁止用户在还未保存修改前突然离开
    beforeRouteLeave (to, from, next) {
        // ...
        // 导航离开该组件的对用路由时调用
        // 可以访问组件实例 `this`
        const answer = window.confirm('Do you really want to leave?')
        if(answer){
            next()
        }else{
            next(false)
        }
    }
}

// 不太具体这个路由元信息不太懂
// 路由元信息-----定义路由的时候可以配置 meta 字段  


// 路由过渡效果
<transtion>
    <router-view></router-view>
</transtion>

transition的四个钩子函数(4个状态)
                --可设置不同name属性值实现每个组件有每个组件的过渡效果
1.enter 
2.enter-active
3.leave-active
4.leave-to


JavaScript 钩子
可以在属性中声明 JavaScript 钩子
<transition
  v-on:before-enter="beforeEnter"
  v-on:enter="enter"
  v-on:after-enter="afterEnter"
  v-on:enter-cancelled="enterCancelled"

  v-on:before-leave="beforeLeave"
  v-on:leave="leave"
  v-on:after-leave="afterLeave"
  v-on:leave-cancelled="leaveCancelled"
>
  <!-- ... -->
</transition>



滚动行为
注意: 这个功能只在支持 history.pushState 的浏览器中可用。
当创建一个 Router 实例，你可以提供一个 scrollBehavior 方法：

const router = new VueRouter({
    routes:[
        // ...
    ],
    // 第一种案例
    scrollBehavior(to, from, savedPosition){
        //return 期望滚动到哪个位置
        return { x: 0, y: 0 }
    },

    // 第二种案例
    // 返回 savedPosition，在按下 后退/前进 按钮时，就会像浏览器的原生表现那样：
    scrollBehavior(to, from, savedPosition){
        if(savedPosition){
            return savedPosition
        }else{
            return { x: 0, y: 0 }
        }
    },

    // 如果你要模拟“滚动到锚点”的行为
    scrollBehavior(to,from,savedPosition){
        if(to.hash){
            return {
                selector:to.hash
            }
        }
    },

    //     异步滚动
    // 2.8.0 新增
    // 你也可以返回一个 Promise 来得出预期的位置描述：
    scrollBehavior (to, from, savedPosition) {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
            resolve({ x: 0, y: 0 })
            }, 500)
        })
    }
})


路由懒加载

###被 Webpack 自动代码分割的异步组件

第一:
const Foo = () => Promise.resolve({/* 组件定义对象 */})

第二: 在webpack 2 中，我们可以使用 动态 import 语法来定义代码分块点(splitpoint):

import('./Foo.vue')  //返回 Promise


+++++++++
###被 Webpack 自动代码分割的异步组件

const Foo = () => import('./Foo.vue') 

在路由配置中什么都不需要改变，只需要像往常一样使用Foo :


const router = new VueRouter({
    routes:[
        {   path:'/foo', component:Foo}
    ]
})


// 把组件按组分块
// 有时候我们想把某个路由下的所有组件都打包在同个异步块 (chunk) 中。只需要使用 命名 chunk，一个特殊的注释语法来提供 chunk name (需要 Webpack > 2.4)。

const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')